﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.PE;
using System.Reflection;

namespace RewriteBeforeAfter
{
    class Program
    {
        static void Main(string[] args)
        {
            MethodInfo writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
            
            string pathBin = @"C:\Projects\JCSE\ELEN7046\Code\CecilILRewrite\CecilILRewrite\MyStupidLittleConsoleApplication\bin\Debug\MyStupidLittleConsoleApplication.exe";

            AssemblyDefinition assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(pathBin);//AssemblyFactory.GetAssembly(pathBin);
            

            //Gets all types of the MainModule of the assembly
            foreach (TypeDefinition type in assembly.MainModule.Types)
            {
                if (type.Name != "<Module>")
                {
                    //Gets all methods of the current type
                    foreach (MethodDefinition method in type.Methods)
                    {
                        //Gets the CilWorker of the method for working with CIL instructions
                       // CilWorker worker = method.Body.CilWorker;
                        ILProcessor worker = method.Body.GetILProcessor();

                        //Creating a sentence according to the current method
                        string sentence;
                        sentence = String.Concat("Code added in before ", method.Name);

                        //Creating a sentence according to the current method
                        string sentenceAfter;
                        sentenceAfter = String.Concat("Code added in after ", method.Name);

                        //Import the Console.WriteLine() method
                        MethodReference writeLine;
                        writeLine = assembly.MainModule.Import(writeLineMethod);

                        //Creates the MSIL instruction for inserting the sentence
                        Instruction insertSentence;
                        insertSentence = worker.Create(OpCodes.Ldstr, sentence);

                        Instruction insertAfterSentence;
                        insertAfterSentence = worker.Create(OpCodes.Ldstr, sentenceAfter);

                        //Creates the CIL instruction for calling the 
                        //Console.WriteLine(string value) method
                        Instruction callWriteLine;
                        callWriteLine = worker.Create(OpCodes.Call, writeLine);


                        //Getting the first instruction of the current method
                        Instruction ins = method.Body.Instructions[0];

                        //Inserts the insertSentence instruction before the first //instruction
                        method.Body.GetILProcessor().InsertBefore(ins, insertSentence);
                        
                        

                        //Inserts the callWriteLineMethod after the //insertSentence instruction
                        worker.InsertAfter(insertSentence, callWriteLine);

                        //Inserts the insertSentence instruction before the first //instruction
                        method.Body.GetILProcessor().InsertAfter(ins, insertAfterSentence);
                    }
                }
            }


            assembly.Write("AGreatnew.exe");
        }
    }
}
